﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using NHibernate;
using NHibernate.Linq;
using NHibernate.Type;
using Spring.Data.NHibernate.Generic.Support;
using Wuqi.Webdiyer;
using NHibernate.Criterion;

namespace Project.Repository
{
    public interface IRepository<T> where T : class
    {
        /// <summary>
        /// 通过主键返回对象
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns></returns>
        T Get(object id);

        /// <summary>
        /// 保存对象
        /// </summary>
        /// <param name="model">实体</param>
        /// <returns></returns>
        object Save(T model);

        /// <summary>
        /// 更新对象
        /// </summary>
        /// <param name="model">实体</param>
        void Update(T model);

        /// <summary>
        /// 保存或更新对象
        /// </summary>
        /// <param name="model">实体</param>
        void SaveOrUpdate(T model);

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="model">实体</param>
        void Delete(T model);

        /// <summary>
        /// 删除对象 : 唐海华新增的
        /// </summary>
        /// <param name="id">主键值</param>
        void Delete(object id);

        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetAll();

        /// <summary>
        /// 动态查询记录
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        IList<T> GetByCriteria(IList<ICriterion> list);

        /// <summary>
        /// 动态查询记录
        /// </summary>
        /// <param name="list">条件查询参数</param>
        /// <param name="order">排序</param>
        /// <returns></returns>
        IList<T> GetByCriteria(IList<ICriterion> list, Order order);

        /// <summary>
        /// 动态查询记录
        /// </summary>
        /// <param name="list">条件查询参数</param>
        /// <param name="order">排序</param>
        /// <returns></returns>
        IList<T> GetByCriteria(IList<ICriterion> list, IList<Order> orderList);

        /// <summary>
        /// 获取记录总数 : 唐海华新增的
        /// </summary>
        /// <returns></returns>
        int GetCount();

        /// <summary>
        /// 获取记录总数 : 唐海华新增的
        /// </summary>
        /// <returns></returns>
        int GetCount(IList<ICriterion> list);

        /// <summary>
        /// 获取分页集合
        /// </summary>
        /// <param name="firstResult">开始记录</param>
        /// <param name="maxResult">行数</param>
        /// <returns></returns>
        IQueryable<T> GetPageList(int firstResult, int maxResult);

        IQueryable<T> FindPageList(System.Reflection.PropertyInfo sort, string dir, int firstResult, int maxResult);

        IQueryable<T> FindPageList(out long total, System.Reflection.PropertyInfo sort, string dir, int firstResult, int maxResult);

        // 新添加的代码 摘自：NHibernateProviderSample，通过<query>的方式查询
        IList<T> FindByNamedQuery(string queryName, object value, IType type);

        IList<T> FindByNamedQuery(string queryName, object[] values, IType[] types);

        // 动态分页查询
        IList<T> GetPageList(int firstResult, int maxResult, IList<ICriterion> list, Order order);

        IList<T> GetPageList(AspNetPager AspNetPager, IList<ICriterion> queryList, Order order);
        IList<T> GetPageList(AspNetPager AspNetPager, IList<ICriterion> queryList, IList<Order> order);

        /// <summary>
        /// 自定义查询(自定义 LINQ 查询语句)
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        IList GetList(string queryString);

        /// <summary>
        /// 自定义查询(查找  Distinct columnName)
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        IList<TT> GetDistinctList<TT>(string columnName);
    }

    /// <summary>
    /// Repository基类
    /// </summary>
    /// <typeparam name="T">实体</typeparam>
    public abstract class Repository<T> : HibernateDaoSupport, IRepository<T> where T : class
    {
        public virtual T Get(object id)
        {
            if (id == null) throw new ArgumentNullException("id");
            return this.HibernateTemplate.Get<T>(id);
        }

        public virtual object Save(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            return this.HibernateTemplate.Save(model);
        }        

        public virtual void Update(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Update(model);
        }

        public virtual void SaveOrUpdate(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.SaveOrUpdate(model);
        }

        public virtual void Delete(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Delete(model);
        }

        public virtual void Delete(object id)
        {
            T model = this.Get(id);
            if (model != null)
            {
                this.HibernateTemplate.Delete(model);
            }
            else
            {
                throw new Exception("不存在的对象");
            }
        }

        public virtual void SubmitChanges()
        {
            this.Session.Flush();
        }

        public virtual IQueryable<T> GetAll()
        {
            return this.Session.Linq<T>();
        }

		public IList<T> GetByCriteria(IList<NHibernate.Criterion.ICriterion> list)
		{
			ICriteria criteria = this.Session.CreateCriteria(typeof(T));

			foreach (var item in list)
			{
				criteria.Add(item);
			}

			return criteria.List<T>();

		}
		public IList<T> GetByCriteria(IList<NHibernate.Criterion.ICriterion> list, IList<NHibernate.Criterion.Order> orderList)
		{
			ICriteria criteria = this.Session.CreateCriteria(typeof(T));

			foreach (var item in list)
			{
				criteria.Add(item);
			}
            // 排序方式
            foreach (var item in orderList)
			{
                criteria.AddOrder(item);
            }

			return criteria.List<T>();

		}
		public IList<T> GetByCriteria(IList<NHibernate.Criterion.ICriterion> list, NHibernate.Criterion.Order order)
		{
			ICriteria criteria = this.Session.CreateCriteria(typeof(T));

			foreach (var item in list)
			{
				criteria.Add(item);
			}
            // 排序方式
            if (order != null)
            {
                criteria.AddOrder(order);
            }

			return criteria.List<T>();

		}
		
		public virtual int GetCount()
        {
            return this.Session.Linq<T>().Count();
        }
		public virtual int GetCount(IList<NHibernate.Criterion.ICriterion> list)
        {
            //return this.Session.Linq<T>().Count();

            // 修改:原方法不能实现条件查询(不知道如何查询),故使用以下方法
            // 通过 log 发现以下转换后的 sql 是通过 sql * from table where 条件 之后计算结果条数,而非使用的是 select count(id) from table
            // 而原方法转换后的sql使用的是 select count(id) from table
            ICriteria criteria = this.Session.CreateCriteria(typeof(T));
            foreach (var item in list)
            {
                criteria.Add(item);
            }
            return criteria.List<T>().Count;
        }

        public virtual IQueryable<T> GetPageList(int firstResult, int maxResult)
        {
            var query = this.Session.Linq<T>().Skip(firstResult).Take(maxResult);
            return query;
        }

        public virtual IQueryable<T> FindAll(PropertyInfo sort, string dir)
        {
            if (sort == null) throw new ArgumentNullException("sort");
            if (dir == null) throw new ArgumentNullException("dir");

            var source = this.Session.Linq<T>();

            string sortingDir = (dir.ToUpper().Trim() == "ASC") ? "OrderBy" : "OrderByDescending";

            ParameterExpression paramOrderBy = System.Linq.Expressions.Expression.Parameter(typeof(T), sort.Name);
            System.Linq.Expressions.Expression exprOrderBy = System.Linq.Expressions.Expression.Call(typeof(Queryable), sortingDir,
                new Type[] { typeof(T), sort.PropertyType },
                source.Expression, System.Linq.Expressions.Expression.Lambda(System.Linq.Expressions.Expression.Property(paramOrderBy, sort.Name), paramOrderBy));
            IQueryable<T> query = source.Provider.CreateQuery<T>(exprOrderBy);

            return query;
        }

        public virtual IQueryable<T> FindPageList(PropertyInfo sort, string dir, int firstResult, int maxResult)
        {
            if (sort == null) throw new ArgumentNullException("sort");
            if (dir == null) throw new ArgumentNullException("dir");

            var source = this.Session.Linq<T>().Skip(firstResult).Take(maxResult);

            string sortingDir = (dir.ToUpper().Trim() == "ASC") ? "OrderBy" : "OrderByDescending";

            ParameterExpression paramOrderBy = System.Linq.Expressions.Expression.Parameter(typeof(T), sort.Name);
            System.Linq.Expressions.Expression exprOrderBy = System.Linq.Expressions.Expression.Call(typeof(Queryable), sortingDir,
                new Type[] { typeof(T), sort.PropertyType },
                source.Expression, System.Linq.Expressions.Expression.Lambda(System.Linq.Expressions.Expression.Property(paramOrderBy, sort.Name), paramOrderBy));
            IQueryable<T> query = source.Provider.CreateQuery<T>(exprOrderBy);

            return query;
        }

        public virtual IQueryable<T> FindPageList(out long total, System.Reflection.PropertyInfo sort, string dir, int firstResult, int maxResult)
        {
            total = this.FindAll(sort, dir).Count<T>();
            return this.FindPageList(sort, dir, firstResult, maxResult);
        }

        // 新添加的代码
        public virtual IList<T> FindByNamedQuery(string queryName, object value, IType type)
        {
            object[] values = new object[] { value };
            IType[] types = new IType[] { type };
            return FindByNamedQuery(queryName, values, types);
        }

        public IList<T> FindByNamedQuery(string queryName, object[] values, IType[] types)
        {
            IList<T> results;

            ISession s = this.Session;
            //try
            //{
            IQuery query = s.GetNamedQuery(queryName);
            if ((null != values) && (null != types))
            {
                for (int i = 0; i < values.Length; i++)
                {
                    query.SetParameter(i, values[i], types[i]);
                }
            }
            results = query.List<T>();
            //}
            //finally
            //{
            //    //CloseSession(s);
            //}

            return results;
        }

        // 动态分页查询
        public IList<T> GetPageList(int firstResult, int maxResult, IList<NHibernate.Criterion.ICriterion> list, NHibernate.Criterion.Order order)
        {
            ICriteria criteria = this.Session.CreateCriteria(typeof(T));

            foreach (var item in list)
            {
                criteria.Add(item);
            }

            criteria.SetFirstResult(firstResult);
            criteria.SetMaxResults(maxResult);

            //total = criteria.List<T>().Count;

            // 排序方式
            if (order != null)
            {
                criteria.AddOrder(order);
            }

            return criteria.List<T>();

        }
        // 动态分页查询
        public  IList<T> GetPageList(AspNetPager AspNetPager, IList<ICriterion> list, NHibernate.Criterion.Order order)
        {
            ICriteria criteria = this.Session.CreateCriteria(typeof(T));
            foreach (var item in list)
            {
                criteria.Add(item);
            }

            AspNetPager.RecordCount = this.GetCount(list);
            int firstResult = (AspNetPager.CurrentPageIndex - 1) * AspNetPager.PageSize;
            int maxResult = AspNetPager.CurrentPageIndex * AspNetPager.PageSize;
            criteria.SetFirstResult(firstResult);
            criteria.SetMaxResults(maxResult);

            // 排序方式
            if (order != null)
            {
                criteria.AddOrder(order);
            }

            return criteria.List<T>();

        }
        public  IList<T> GetPageList(AspNetPager AspNetPager, IList<ICriterion> list, IList<Order> orderList)
        {
            ICriteria criteria = this.Session.CreateCriteria(typeof(T));
            foreach (var item in list)
            {
                criteria.Add(item);
            }

            AspNetPager.RecordCount = this.GetCount(list);
            int firstResult = (AspNetPager.CurrentPageIndex - 1) * AspNetPager.PageSize;
            int maxResult = AspNetPager.CurrentPageIndex * AspNetPager.PageSize;
            criteria.SetFirstResult(firstResult);
            criteria.SetMaxResults(maxResult);

            // 排序方式
            foreach (var item in orderList)
            {
                criteria.AddOrder(item);
            }

            return criteria.List<T>();

        }

        public IList GetList(string queryString)
        {
            string hql = queryString;
            IQuery query = this.Session.CreateQuery(hql);
            return query.List();
        }

        public IList<TT> GetDistinctList<TT>(string columnName)
        {
            string tableName = typeof(T).Name;
            string hql = "select distinct " + columnName + " from " + tableName + " k";
            IQuery query = this.Session.CreateQuery(hql);
            return query.List<TT>();
        }
    }
}
